package com.tianji.promotion.utils;

import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.EnumMap;
import java.util.Map;
import java.util.function.Function;

/**
 * @author : Cammy.Wu
 * Description : 锁工厂
 */

/**
 * todo:自定义锁工厂类，用于根据不同的锁类型生成对应的锁实例。
 * 该类使用 Redisson 客户端来创建不同类型的锁，包括可重入锁、公平锁、读锁和写锁。
 */
@Component
public class MyLockFactory {

    /**
     * 存储不同锁类型及其对应的锁创建函数的映射。
     * 键为 MyLockType 枚举类型，表示锁的类型。
     * 值为 Function<String, RLock> 类型的函数，用于根据锁的名称创建对应的 RLock 实例。
     */
    private final Map<MyLockType, Function<String, RLock>> lockHandlers;

    /**
     * 构造函数，初始化锁处理程序映射。
     *
     * @param redissonClient Redisson 客户端实例，用于创建不同类型的锁。
     */
    public MyLockFactory(RedissonClient redissonClient) {
        // 使用 EnumMap 存储锁类型和对应的锁创建函数，EnumMap 是专门为枚举类型设计的 Map，性能较高
        this.lockHandlers = new EnumMap<>(MyLockType.class);
        // 为读锁类型添加处理函数，使用 Redisson 客户端的 getLock 方法创建锁
        this.lockHandlers.put(MyLockType.READ_LOCK, redissonClient::getLock);
        // 为公平锁类型添加处理函数，使用 Redisson 客户端的 getFairLock 方法创建公平锁
        this.lockHandlers.put(MyLockType.FAIR_LOCK, redissonClient::getFairLock);
        // 这里再次为读锁类型添加处理函数，会覆盖之前的读锁处理函数，
        // 使用 Redisson 客户端的 getReadWriteLock 方法获取读写锁，并返回读锁
        this.lockHandlers.put(MyLockType.READ_LOCK, name -> redissonClient.getReadWriteLock(name).readLock());
        // 为写锁类型添加处理函数，使用 Redisson 客户端的 getReadWriteLock 方法获取读写锁，并返回写锁
        this.lockHandlers.put(MyLockType.WRITE_LOCK, name -> redissonClient.getReadWriteLock(name).writeLock());
    }

    /**
     * 根据指定的锁类型和锁名称获取对应的锁实例。
     *
     * @param lockType 锁的类型，为 MyLockType 枚举类型。
     * @param name     锁的名称，用于标识锁。
     * @return 对应的 RLock 实例，可用于加锁和解锁操作。
     */
    public RLock getLock(MyLockType lockType, String name) {
        // 从锁处理程序映射中获取对应锁类型的处理函数，并应用锁名称生成锁实例
        return lockHandlers.get(lockType).apply(name);
    }
}

